package com.example.mybatisplusproject.plugins;

import com.example.mybatisplusproject.annotation.EncryptDecryptClass;
import com.example.mybatisplusproject.endecrypt.IEncryptDecrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;

/**
 * @author zls
 * @date 2021/8/1 8:52 下午
 * 加密拦截器
 */
@Intercepts({
        @Signature(
        type = ParameterHandler.class,
        method = "setParameters",  // 这里的method指的是要拦截ParameterHandler的哪个方法，一般只用拦截设置参数的方法即可
        args = PreparedStatement.class // 这里的args指的是拦截方法的参数
    )
})
@Component
@Slf4j
public class EncryptInterceptor implements Interceptor {

    @Autowired
    private IEncryptDecrypt encryptDecrypt;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.info("进入加密拦截器拦截方法中.....");
        if(invocation.getTarget() instanceof ParameterHandler) {
            ParameterHandler parameterHandler = (ParameterHandler)invocation.getTarget();
            // getDeclaredFields()：获得某个类的所有声明的字段，即包括public、private和proteced，但是不包括父类的申明字段
            // getFields()：获得某个类的所有的公共（public）的字段
            Field field = parameterHandler.getClass().getDeclaredField("parameterObject");
            field.setAccessible(true);
            Object o = field.get(parameterHandler);
            if(o != null) {
                Class<?> aClass = o.getClass();
                EncryptDecryptClass annotation = AnnotationUtils.findAnnotation(aClass, EncryptDecryptClass.class);
                if(annotation != null) {
                    Field[] fields = o.getClass().getDeclaredFields();
                    encryptDecrypt.encrypt(fields, o);
                }
            }
        }
        return invocation.proceed();
    }
}
